#include "person.h"
#include "building.h"   // We needs to do this to avoid a circular declaration problem
#include "levelscene.h"


Person::Person(PathMap *mapper, QPixmap personPixmap, LevelScene *parent, QGraphicsScene *scene)
    : QObject(parent), QGraphicsPixmapItem(personPixmap)
{
    scene->addItem(this);
    setData(ITEM_TYPE,GameItems::Person);

    overlayPixmap = personPixmap;
    overlayPixmap.fill(QColor(42,255,0,128));
    overlayPixmap.setAlphaChannel(pixmap().alphaChannel());
    setOffset(-boundingRect().width()/2,0);
    setFlag(QGraphicsItem::ItemIsSelectable);

    virus = 0;

    // Create the stats object for the person
    stats = new PersonStats();

    currentBuilding = 0;

    pathMap = mapper;
    pathLocation = 0;

    parentScene = parent;

    inBuilding = true;
    setVisible(false);
    wasBlocked = false;

    // Generate a speed between .05 to .25
    speed = ((rand() % 200) / 1000.0) + .05;
}

Person::~Person()
{
}

void Person::timerEvent(QTimerEvent *)
{
    killTimer(timerID);

    int x,y;

    if (path.size()>0)  // if we have a path, set the starting location to the precious node, else set it to the current location of the person
    {
        pathMap->StateToXY(path.at(pathLocation-1),x,y);
        path.clear();
        pathLocation = 0;
    }
    else
    {
        x = currentBuilding->getEnterencePoint().x();
        y = currentBuilding->getEnterencePoint().y();
    }

    if (parentScene->leaveBuilding(this, currentBuilding, wasBlocked))
    {
        previousBuilding = currentBuilding;
        //get a new random building that is not the building we are in right now
        int newBuildingID = (rand() % parentScene->buildings.length());
        while (currentBuilding == parentScene->buildings.at(newBuildingID))
            newBuildingID = (rand() % parentScene->buildings.length());

        currentBuilding = parentScene->buildings.at(newBuildingID);
        emit solvePath(QPoint(x,y),currentBuilding->getEnterencePoint(),this);
        inBuilding = false;
    }
    else
        timerID = startTimer(20000 + ((rand() % 16000)-8000));
}

void Person::startPerson()
{
    if (inBuilding)
        timerID = startTimer(rand() % 30000);
}

void Person::stopPerson()
{
    if (inBuilding)
        killTimer(timerID);
}

void Person::treatPerson()
{
    //Something will eventually happen here
}

void Person::advance(int phase)
{
    if (phase == 0)
    {
        //Do damage to the virus and have the virus do damage to me if I have the virus
        if (virus != 0)
        {
            stats->setHP(stats->getHP() + (stats->getImmuneStrength() / 500.0));
            stats->setHP(stats->getHP() - ((virus->Virulence) / 375.0));

            virus->setHP(virus->getHP() + (virus->ImmuneResistance / 500.0));
            virus->setHP(virus->getHP() - ((stats->getImmuneResponse() + stats->getGammaglobulins()) / 375.0));

            //qDebug("person H: %f, Person Strengh: %d, virus HP: %f, Virulence: %d",stats->getHP(),stats->getImmuneStrength(),virus->HP,virus->Virulence);
            // If the virus's HP is less that 0.00001 kill the virus
            if (virus->HP < 0.00001)
            {
                delete virus;
                virus = 0;
            }

            // If my HP is less that 0.00001, then kill me
            if (stats->getHP() < 0.00001)
            {
                parentScene->removePerson(this);
                return;
            }

        }

        stats->itterateGammagloubulins();
        //Move person along path
        if (path.size() > 0)
        {
            if ((unsigned int)(pathLocation + 1) < path.size())
            {
                int x,y;

                pathMap->StateToXY(path.at((unsigned int)pathLocation),x,y);
                if (pathMap->IsPointPassable(x,y))
                {
                    int prevX, prevY, nextX, nextY;
                    double localMovement;

                    pathMap->StateToXY(path.at((int)pathLocation), prevX, prevY);
                    pathMap->StateToXY(path.at((int)pathLocation + 1), nextX, nextY);
                    localMovement = pathLocation - (int)pathLocation;

                    double moveX, moveY;
                    moveX = localMovement * (nextX - prevX);
                    moveY = localMovement * (nextY - prevY);

                    setPos((moveX + prevX) * 10, (moveY + prevY) * 10);
                    pathLocation += speed;
                }
                else
                {
                    // if we run into a road block, turn around and find a new building
                    wasBlocked = true;
                    timerID = startTimer(0);
                }
            }

            if ((pathLocation > path.size()-2) && (path.size()>0))
                arrive();
        }
    }
}

bool Person::GetInBuilding()
{
    return inBuilding;
}

void Person::collidesWithPerson(Person *colliding)
{
    //==== Transmit a virus if possible ====
    // To decide if a transmission happens, the resistance of the non-infected person is subtracted from the infectivity
    // of the infecting virus. If the result is 0 or less, the virus is not transmitted. If the result is larger than 0
    // the virus has a ((infectivity - resistance) / divisor) percent chance of tranmitting the desease. The divisor is
    // there account for the fact that roughly 20 collision events are called every time two people meet on the street.
    // Infectivity of the virus is reduced by the cleanliness of the person
    if ((virus!=0) && (colliding->virus == 0))  // If we have the virus and they don't
    {
        if ((virus->Infectivity - stats->getCleanliness() - colliding->stats->getResistence()) > 0)   // If the virus overpowers the persons immunity
        {
            if ((rand()%1000 + 1) < (virus->Infectivity - colliding->stats->getResistence())/4) // Random chance that the virus will transmit
            {
                colliding->virus = new Virus(virus,colliding);
            }
        }
    }
    else if ((virus == 0) && (colliding->virus != 0))   // If they have a virus and we don't
    {
        if ((colliding->virus->Infectivity - colliding->stats->getCleanliness() - stats->getResistence()) > 0)   // If the virus overpowers the persons immunity
        {
            if ((rand()%1000 + 1) < (colliding->virus->Infectivity - stats->getResistence())/4) // Random chance that the virus will transmit
            {
                virus = new Virus(colliding->virus,this);
            }
        }
    }
}

Building * Person::getCurrentBuilding()
{
    return currentBuilding;
}

void Person::setCurrentBuilding(Building *newBuilding)
{
    currentBuilding = newBuilding;
}

bool Person::isInBuilding()
{
    return inBuilding;
}

void Person::setPath(std::vector<void *>newPath)
{
    if (newPath.size() == 0)    // if the path is empty, then go to a new building.
    {
        currentBuilding = previousBuilding;
        timerID = startTimer(0);
    }
    else
    {
        path = newPath;
        wasBlocked = false;
        setVisible(true);
        pathLocation = 0;
    }
}

void Person::arrive()
{
    parentScene->enterBuilding(this,currentBuilding);
    setVisible(false);
    inBuilding = true;
    path.clear();
    timerID = startTimer(20000 + ((rand() % 16000)-8000));
}

void Person::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    QGraphicsPixmapItem::paint(painter,option,widget);

    if (virus != 0)
        painter->drawPixmap(offset(),overlayPixmap);
}

